#pragma once
#include <QQuickView>
#include <QMouseEvent>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QCoreApplication>
#include <osgViewer/Viewer>
#include <osgViewer/GraphicsWindow>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>

class OsgQWindow : public QWindow {
public:
	OsgQWindow(int x, int y, int width, int height) {
		setSurfaceType(QQuickView::SurfaceType::OpenGLSurface);

		QSurfaceFormat format;
		format.setProfile(QSurfaceFormat::CoreProfile);
		format.setVersion(4, 6);
		format.setSamples(4);
		setFormat(format);

		setPosition(x, y);
		resize(width, height);

		create();// Allocates the platform resources associated with the window.

		m_glContext = new QOpenGLContext;
		m_glContext->setFormat(format);
		if (!m_glContext->create()) qCritical() << "QOpenGLContext::create fail!!!";
		if (!m_glContext->makeCurrent(this)) qCritical() << "QOpenGLContext::makeCurrent fail!!!";

		QOpenGLFunctions glFunctions(m_glContext);
		glFunctions.initializeOpenGLFunctions();

		qDebug() << "OpenGL Version:" << (const char*)glFunctions.glGetString(GL_VERSION);

		m_viewer = new osgViewer::Viewer;

		auto embedWindow = m_viewer->setUpViewerAsEmbeddedInWindow(x, y, width, height);
		m_eventQueue = embedWindow->getEventQueue();

		m_viewer->setCameraManipulator(new osgGA::TrackballManipulator);
		m_viewer->addEventHandler(new osgViewer::StatsHandler);

		m_viewer->realize();
	}

	void show(osg::Node* scene) {
		m_viewer->setSceneData(scene);
		QWindow::show();
		doRendering();
	}

protected:
	void doRendering() {
		while (!isExposed())
			QCoreApplication::processEvents();

		while (!m_viewer->done()) {
			// Key Point: Bind Qt context to each frame
			if (!m_glContext->makeCurrent(this)) {
				if (isActive())
					qCritical() << "Failed to make context current inside loop";
				break;
			}

			m_viewer->frame();

			// Swap the buffer before and after, and submit the rendering result
			m_glContext->swapBuffers(this);

			//qtContext.doneCurrent();

			QCoreApplication::processEvents();
		}
	}

	void mousePressEvent(QMouseEvent* event) override {
		m_eventQueue->mouseButtonPress(event->x(), event->y(), convertQtMouseButton(event->button()));
	}

	void mouseReleaseEvent(QMouseEvent* event) override {
		m_eventQueue->mouseButtonRelease(event->x(), event->y(), convertQtMouseButton(event->button()));
	}

	void mouseMoveEvent(QMouseEvent* event) override {
		m_eventQueue->mouseMotion(event->x(), event->y());
	}

	void keyPressEvent(QKeyEvent* event) override {
		m_eventQueue->keyPress(osgGA::GUIEventAdapter::KeySymbol(event->key()));
	}

	void keyReleaseEvent(QKeyEvent* event) override {
		m_eventQueue->keyRelease(osgGA::GUIEventAdapter::KeySymbol(event->key()));
	}

private:
	int convertQtMouseButton(Qt::MouseButton button) {
		switch (button) {
			case Qt::LeftButton: return 1;
			case Qt::MiddleButton: return 2;
			case Qt::RightButton: return 3;
			default: return 0;
		}
	}

	QOpenGLContext* m_glContext;
	osgViewer::Viewer* m_viewer;
	osgGA::EventQueue* m_eventQueue;
};